package com.zhang.novel.service.impl;

import com.github.pagehelper.PageHelper;
import com.google.common.base.Charsets;
import com.zhang.novel.core.bean.UserDetails;
import com.zhang.novel.core.enums.ResponseStatus;
import com.zhang.novel.core.exception.BusinessException;
import com.zhang.novel.core.utils.BeanUtil;
import com.zhang.novel.core.utils.CookieUtil;
import com.zhang.novel.core.utils.IdWorker;
import com.zhang.novel.core.utils.MD5Util;
import com.zhang.novel.entity.*;
import com.zhang.novel.entity.User;
import com.zhang.novel.form.UserForm;
import com.zhang.novel.mapper.*;
import com.zhang.novel.service.UserService;
import com.zhang.novel.vo.BookReadHistoryVO;
import com.zhang.novel.vo.BookShelfVO;
import com.zhang.novel.vo.UserFeedbackVO;
import lombok.RequiredArgsConstructor;
import org.mybatis.dynamic.sql.delete.render.DeleteStatementProvider;
import org.mybatis.dynamic.sql.render.RenderingStrategies;
import org.mybatis.dynamic.sql.select.render.SelectStatementProvider;
import org.mybatis.dynamic.sql.update.render.UpdateStatementProvider;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;

import static com.zhang.novel.mapper.UserBookshelfDynamicSqlSupport.userBookshelf;
import static com.zhang.novel.mapper.UserBuyRecordDynamicSqlSupport.userBuyRecord;
import static com.zhang.novel.mapper.UserDynamicSqlSupport.*;
import static com.zhang.novel.mapper.UserFeedbackDynamicSqlSupport.userFeedback;
import static com.zhang.novel.mapper.UserReadHistoryDynamicSqlSupport.userReadHistory;
import static org.mybatis.dynamic.sql.SqlBuilder.*;
import static org.mybatis.dynamic.sql.select.SelectDSL.select;

@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {

    private final UserMapper userMapper;

    private final FrontUserBookshelfMapper userBookshelfMapper;

    private final FrontUserReadHistoryMapper userReadHistoryMapper;

    private final UserFeedbackMapper userFeedbackMapper;

    private final UserBuyRecordMapper userBuyRecordMapper;

    @Override
    public UserDetails login(UserForm form) {
        SelectStatementProvider selectStatementProvider = select(id, username, nickName)
                .from(user)
                .where(username, isEqualTo(form.getUsername()))
                .and(password, isEqualTo(MD5Util.MD5Encode(form.getPassword(), Charsets.UTF_8.name())))
                .build()
                .render(RenderingStrategies.MYBATIS3);
        List<User> users = userMapper.selectMany(selectStatementProvider);
        if (users.isEmpty()) {
            throw new BusinessException(ResponseStatus.USERNAME_PASSWORD_ERROR);
        }
        //生成UserDetails对象并返回
        UserDetails userDetails = new UserDetails();
        User user = users.get(0);
        userDetails.setId(user.getId());
        userDetails.setUsername(user.getUsername());
        userDetails.setNickName(user.getNickName());

        return userDetails;
    }

    @Override
    public UserDetails register(UserForm form) {
        // 查询用户是否已经注册
        SelectStatementProvider selectStatementProvider = select(count(id))
                .from(UserDynamicSqlSupport.user)
                .where(username, isEqualTo(form.getUsername()))
                .build()
                .render(RenderingStrategies.MYBATIS3);
        long count = userMapper.count(selectStatementProvider);
        if (count > 0) {
            // 用户已存在
            throw new BusinessException(ResponseStatus.USERNAME_EXIST);
        }
        User entity = new User();
        BeanUtils.copyProperties(form, entity);

        //保存用户到数据库
        long id = new IdWorker().nextId();
        entity.setId(id);
        entity.setNickName(entity.getUsername());
        Date currentDate = new Date();
        entity.setCreateTime(currentDate);
        entity.setUpdateTime(currentDate);
        entity.setPassword(MD5Util.MD5Encode(entity.getPassword(), Charsets.UTF_8.name()));
        userMapper.insertSelective(entity);

        //生成UserDetails对象并返回
        UserDetails userDetails = new UserDetails();
        userDetails.setId(id);
        userDetails.setUsername(entity.getUsername());
        userDetails.setNickName(entity.getNickName());

        return userDetails;
    }

    @Override
    public Boolean queryIsInShelf(Long userId, Long bookId) {
        SelectStatementProvider selectStatementProvider = select(count(id))
                .from(userBookshelf)
                .where(UserBookshelfDynamicSqlSupport.bookId, isEqualTo(bookId))
                .build()
                .render(RenderingStrategies.MYBATIS3);
        return userBookshelfMapper.count(selectStatementProvider) > 0;
    }

    @Override
    public void addToBookShelf(Long userId, Long bookId, Long preContentId) {
        // 判断书架是否已经存在改小说
        if (!queryIsInShelf(userId, bookId)) {
            UserBookshelf userBookshelf = new UserBookshelf();
            userBookshelf.setUserId(userId);
            userBookshelf.setBookId(bookId);
            userBookshelf.setPreContentId(preContentId);
            userBookshelf.setCreateTime(new Date());

            userBookshelfMapper.insert(userBookshelf);
        }
    }

    @Override
    public void removeFromBookShelf(Long userId, Long bookId) {
        DeleteStatementProvider deleteStatementProvider = deleteFrom(userBookshelf)
                .where(UserBookshelfDynamicSqlSupport.userId, isEqualTo(userId))
                .and(UserBookshelfDynamicSqlSupport.bookId, isEqualTo(bookId))
                .build()
                .render(RenderingStrategies.MYBATIS3);
        userBookshelfMapper.delete(deleteStatementProvider);
    }

    @Override
    public List<BookShelfVO> listBookShelfByPage(Long userId, int page, int pageSize) {
        PageHelper.startPage(page, pageSize);
        return userBookshelfMapper.listBookShelf(userId);
    }

    @Override
    public List<BookReadHistoryVO> listReadHistoryByPage(Long userId, int page, int pageSize) {
        PageHelper.startPage(page, pageSize);
        return userReadHistoryMapper.listReadHistory(userId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addReadHistory(Long userId, Long bookId, Long preContentId) {
        // 查询用户以前在该书是否存在阅读记录
        SelectStatementProvider selectStatementProvider = select(count(id))
                .from(userReadHistory)
                .where(UserReadHistoryDynamicSqlSupport.userId, isEqualTo(userId))
                .and(UserReadHistoryDynamicSqlSupport.bookId, isEqualTo(bookId))
                .build()
                .render(RenderingStrategies.MYBATIS3);
        long count = userReadHistoryMapper.count(selectStatementProvider);
        Date currentDate = new Date();
        if (count > 0) {
            // 存在，直接修改
            UpdateStatementProvider updateStatementProvider = update(userReadHistory)
                    .set(UserReadHistoryDynamicSqlSupport.preContentId)
                    .equalTo(preContentId)
                    .set(UserReadHistoryDynamicSqlSupport.updateTime)
                    .equalTo(currentDate)
                    .where(UserReadHistoryDynamicSqlSupport.userId, isEqualTo(userId))
                    .and(UserReadHistoryDynamicSqlSupport.bookId, isEqualTo(bookId))
                    .build()
                    .render(RenderingStrategies.MYBATIS3);
            userReadHistoryMapper.update(updateStatementProvider);
        } else {
            //插入该书新的历史记录
            UserReadHistory userReadHistory = new UserReadHistory();
            userReadHistory.setBookId(bookId);
            userReadHistory.setUserId(userId);
            userReadHistory.setPreContentId(preContentId);
            userReadHistory.setCreateTime(currentDate);
            userReadHistory.setUpdateTime(currentDate);
            userReadHistoryMapper.insertSelective(userReadHistory);
        }

        //更新书架的阅读历史
        UpdateStatementProvider updateStatement = update(userBookshelf)
                .set(UserBookshelfDynamicSqlSupport.preContentId)
                .equalTo(preContentId)
                .set(UserBookshelfDynamicSqlSupport.updateTime)
                .equalTo(currentDate)
                .where(UserBookshelfDynamicSqlSupport.userId, isEqualTo(userId))
                .and(UserBookshelfDynamicSqlSupport.bookId, isEqualTo(bookId))
                .build()
                .render(RenderingStrategies.MYBATIS3);

        userBookshelfMapper.update(updateStatement);
    }

    @Override
    public void addFeedBack(Long userId, String content) {
        UserFeedback feedback = new UserFeedbackVO();
        feedback.setUserId(userId);
        feedback.setContent(content);
        feedback.setCreateTime(new Date());

        userFeedbackMapper.insertSelective(feedback);
    }

    @Override
    public List<UserFeedbackVO> listUserFeedBackByPage(Long userId, int page, int pageSize) {
        PageHelper.startPage(page, pageSize);
        SelectStatementProvider selectStatementProvider = select(UserFeedbackDynamicSqlSupport.content, UserFeedbackDynamicSqlSupport.createTime)
                .from(userFeedback)
                .where(UserFeedbackDynamicSqlSupport.userId, isEqualTo(userId))
                .orderBy(UserFeedbackDynamicSqlSupport.id.descending())
                .build().render(RenderingStrategies.MYBATIS3);
        return BeanUtil.copyList(userFeedbackMapper.selectMany(selectStatementProvider), UserFeedbackVO.class);
    }

    @Override
    public User userInfo(Long userId) {
        SelectStatementProvider selectStatementProvider = select(id, username, nickName, userPhoto, userSex, accountBalance)
                .from(user)
                .where(id, isEqualTo(userId))
                .build()
                .render(RenderingStrategies.MYBATIS3);
        return userMapper.selectMany(selectStatementProvider).get(0);
    }

    @Override
    public void updateUserInfo(Long userId, User user) {
        User updateUser = new User();
        updateUser.setId(userId);
        updateUser.setNickName(user.getNickName());
        updateUser.setUserSex(user.getUserSex());
        updateUser.setUpdateTime(new Date());
        userMapper.updateByPrimaryKeySelective(updateUser);
    }

    @Override
    public void updatePassword(Long userId, String oldPassword, String newPassword) {
        SelectStatementProvider selectStatement = select(password)
                .from(user)
                .where(id, isEqualTo(userId))
                .build()
                .render(RenderingStrategies.MYBATIS3);
        if (!userMapper.selectMany(selectStatement).get(0).getPassword().equals(MD5Util.MD5Encode(oldPassword, Charsets.UTF_8.name()))) {
            throw new BusinessException(ResponseStatus.OLD_PASSWORD_ERROR);
        }
        UpdateStatementProvider updateStatement = update(user)
                .set(password)
                .equalTo(MD5Util.MD5Encode(newPassword, Charsets.UTF_8.name()))
                .where(id, isEqualTo(userId))
                .build()
                .render(RenderingStrategies.MYBATIS3);
        userMapper.update(updateStatement);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void buyBookIndex(Long userId, UserBuyRecord buyRecord) {
        // 查询用户余额
        SelectStatementProvider selectStatementProvider = select(accountBalance)
                .from(user)
                .where(id, isEqualTo(userId))
                .build()
                .render(RenderingStrategies.MYBATIS3);
        User user = userMapper.selectMany(selectStatementProvider).get(0);
        if (10 > user.getAccountBalance()) {
            throw new BusinessException(ResponseStatus.USER_NO_BALANCE);
        }
        buyRecord.setUserId(userId);
        buyRecord.setCreateTime(new Date());
        buyRecord.setBuyAmount(10);

        // 生成消费记录
        userBuyRecordMapper.insertSelective(buyRecord);

        //减少用户余额
        user.setAccountBalance(user.getAccountBalance() - 10);
        userMapper.updateByPrimaryKey(user);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addAmount(Long userId, int totalAmount) {
        User user = this.userInfo(userId);
        user.setId(userId);
        user.setAccountBalance(user.getAccountBalance() + totalAmount);
        userMapper.updateByPrimaryKeySelective(user);
    }

    @Override
    public Boolean queryIsBuyBookIndex(Long userId, Long bookIndexId) {
        SelectStatementProvider selectStatementProvider = select(count(id))
                .from(userBuyRecord)
                .where(UserBuyRecordDynamicSqlSupport.userId, isEqualTo(userId))
                .and(UserBuyRecordDynamicSqlSupport.bookIndexId, isEqualTo(bookIndexId))
                .build()
                .render(RenderingStrategies.MYBATIS3);
        return userBuyRecordMapper.count(selectStatementProvider) > 0;
    }
}
